package com.otp.webapp.action;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.appfuse.model.User;
import org.appfuse.service.MailEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Component;

import com.otp.model.test.instance.TestInstance;
import com.otp.model.test.instance.TestItemResponseInstance;
import com.otp.model.test.template.Item;
import com.otp.model.test.template.ResponseScoreOption;
import com.otp.model.test.template.TestSection;
import com.otp.model.test.template.TestTemplate;
import com.otp.service.instance.ItemManager;
import com.otp.service.instance.ResponseScoreOptionManager;
import com.otp.service.instance.TestInstanceManager;
import com.otp.service.instance.TestSectionManager;
import com.otp.webapp.comparators.CompTestItemResponseInstancesByOrder;
import com.otp.webapp.comparators.CompTestItemResponseInstancesBySectionAndOrderInSection;
import com.otp.webapp.util.RequestUtil;

/**
 * JSF Page class to handle editing a user with a form.
 *
 */
@Scope("session")
@Component("reviewTest")
public class ReviewTest extends BasePage implements Serializable {

	///////////////////////// Fields //////////////////////////////////////
	private static final long serialVersionUID = -1141119853856863204L;
	private TestInstance testInstance;
	private TestTemplate testTemplate;
	private TestInstanceManager testInstanceManager;
	private TestSectionManager testSectionManager;
	private ResponseScoreOptionManager responseScoreOptionManager;
	private ItemManager itemManager;
	private SimpleMailMessage message;

	private List<AnsweredItem> currentAnswerItems;
	private List<List<AnsweredItem>> allAnswItems = new ArrayList<List<AnsweredItem>>();

	@SuppressWarnings("unused")
	private boolean table=false;
	private boolean testCompleted;

	//variable corresponding to score details
	private List<DisplayTestResult> displayTestResults = new ArrayList<DisplayTestResult>();

	Integer totalSections=0;
	int currentSectionPos;
	//Test details
	//Hashmap to hold all the MapItemTestEntry
	Map<Long,TestSection> mapSections = new HashMap<Long,TestSection>();
	Map<Long,Boolean> renderSections = new HashMap<Long,Boolean>();
	//Answer details
	//HashMap to store answers
	Map<Integer,String> answers = new HashMap<Integer,String>();

	private List<TestItemResponseInstance> instanceItemResponses = new ArrayList<TestItemResponseInstance>();

	private String algorithm;

	private int blockSize=15;

	/////////////////// Setters and Getters ///////////////////////////////

	public TestInstance getTestInstance() {
		return testInstance;
	}

	public void setTestInstance(TestInstance testInstance) {
		this.testInstance = testInstance;
	}

	public List<DisplayTestResult> getDisplayTestResult() {
		return displayTestResults;
	}

	public void setDisplayTestResult(List<DisplayTestResult> displayTestResult) {
		this.displayTestResults = displayTestResult;
	}

	public boolean isSubmitTest() {
		if(currentSectionPos==new Long(totalSections)) return true;
		return false;
	}

	public boolean isBySection() {
		if(algorithm==null||algorithm.equals("")) {System.out.println("No algorithm defined in method bySection()"); return true;}
		if(algorithm.equals("STANDARD_NON_ADAPTIVE")||
		   algorithm.equals("STATIC_DICHOTOMOUS")||
		   algorithm.equals("STATIC_POLYTOMOUS")) return true;
		else return false;
	}

	public boolean isTable() {
		return true;
	}

	public void setTable(boolean table) {
		this.table = table;
	}

	public String getCurrentSectionDescription() {
		if(isBySection()) return "Section: "+(currentSectionPos+1)+" out of "+totalSections;
		else return "Page: "+(currentSectionPos+1)+" out of "+totalSections;
	}

	public List<AnsweredItem> getCurrentAnswerItems() {
		return currentAnswerItems;
	}

	public void setCurrentAnswerItems(List<AnsweredItem> currentAnswerItems) {
		this.currentAnswerItems = currentAnswerItems;
	}

	public boolean isTestCompleted() {
		return testCompleted;
	}

	public void setTestCompleted(boolean testCompleted) {
		this.testCompleted = testCompleted;
	}

	public boolean isPrevious() {
		return currentSectionPos>0;
	}

	public boolean isNext() {
		return currentSectionPos<totalSections-1;
	}

	public Integer getTotalSections() {
		return totalSections;
	}

	////////////////////// DB managers ////////////////////////////////////////////

	@Autowired
	public void setItemManager(@Qualifier("itemManager") ItemManager itemManager) {
		this.itemManager = itemManager;
	}

	@Autowired
	public void setTestInstanceManager(@Qualifier("testInstanceManager")TestInstanceManager testInstancesManager) {
		this.testInstanceManager = testInstancesManager;
	}

	@Autowired
	public void setTestSectionManager(@Qualifier("testSectionManager")TestSectionManager testSectionsManager) {
		this.testSectionManager = testSectionsManager;
	}

	@Autowired
	public void setResponseScoreOptionManager(@Qualifier("responseScoreOptionManager")ResponseScoreOptionManager responseScoreOptionManager) {
		this.responseScoreOptionManager = responseScoreOptionManager;
	}

	@Autowired
	public void setMailEngine(@Qualifier("mailEngine")MailEngine mailEngine) {
		this.mailEngine = mailEngine;
	}

	@Autowired
	public void setMessage(@Qualifier("mailMessage")SimpleMailMessage message){
		this.message=message;
	}

	/////////////////// main methods ///////////////////////////////////////


	public String showResult() {
		return reviewTest();
	}


	public String reviewTest() {

		reinitializeVariables();
		HttpServletRequest request = getRequest();
		String testInstanceId = request.getParameter("testInstanceObjectId");

		if (testInstanceId != null) {
			testInstance =testInstanceManager.get(new Long(testInstanceId));
			testTemplate = testInstance.getTestTemplate();
			algorithm = testInstance.getTestScoringAlgorithm().getAlgorithm();				

			instanceItemResponses = testInstanceManager.getTestItemResponseInstances(testInstanceId);
			//TODO sorting below is problematic
			//Results in "org.hibernate.LazyInitializationException - Could not initialize proxy - no Session" error
							if(isBySection()) Collections.sort(instanceItemResponses, 
									new CompTestItemResponseInstancesBySectionAndOrderInSection());
							else Collections.sort(instanceItemResponses,
									new CompTestItemResponseInstancesByOrder());

			List<Integer> subSectSzs = new ArrayList<Integer>();

			if(isBySection()){	            
				List<TestSection> sections = testSectionManager.getTestSectionByTemplate(testTemplate.getObjectId()+"");
				for(TestSection sect:sections) subSectSzs.add(itemManager.getTestMapEntryBySection(sect.getObjectId()+"").size());
			}
			else{
				int count = instanceItemResponses.size()/blockSize;
				for(int i=0; i<count; i++) subSectSzs.add(blockSize);
				if(!(instanceItemResponses.size()%blockSize==0)) subSectSzs.add(instanceItemResponses.size()-count*blockSize);
			}

			totalSections=subSectSzs.size();
			allAnswItems.clear();
			for(int sz:subSectSzs){
				List<AnsweredItem> sublist = new ArrayList<AnsweredItem>();
				for(int j=0; j<sz; j++){	            		
					TestItemResponseInstance response = instanceItemResponses.remove(0);
					Item itm = response.getRelatedItem();
					String optRange = itm.getResponseScoreRange().getObjectId()+"";
					List<ResponseScoreOption> options = responseScoreOptionManager.getResponseOptionByRangeId(optRange);//TODO move this to AnsweredItem class
					AnsweredItem ansItm = new AnsweredItem(itm, 0, testInstance, options);
					String selection = response.getRelatedResponseOption().getDescription();
					ansItm.setSelectionAndUpdate(selection);

					sublist.add(ansItm);
				}
				allAnswItems.add(sublist);
			}

			currentSectionPos=0;

			currentAnswerItems=allAnswItems.get(currentSectionPos);


			return "reviewTest";
		}
		return null;
	}


	private void reinitializeVariables() {

		displayTestResults = new ArrayList<DisplayTestResult>();
		totalSections=0;	
		mapSections = new HashMap<Long,TestSection>();
		renderSections = new HashMap<Long,Boolean>();
		currentSectionPos = 0;
		instanceItemResponses = new ArrayList<TestItemResponseInstance>();
	}


	public String prev(){
		currentSectionPos--;
		currentAnswerItems = allAnswItems.get(currentSectionPos);
		return null;}


	public String next(){
		currentSectionPos++;
		if(currentSectionPos==totalSections) return "resultDone";
		currentAnswerItems = allAnswItems.get(currentSectionPos);
		return null;
	}

	public String reminderEmail(){
		HttpServletRequest request = getRequest();
		String testInstanceId = request.getParameter("testInstanceObjectId");

		User user=null;
		if (testInstanceId != null) {
			testInstance =testInstanceManager.get(new Long(testInstanceId));
			user=testInstance.getAppUser();
		}
		else return "errorPage";

        try {
        	message.setSubject(getText("review.test.reminder.email.subject"));
        	setTemplateName("reminder.vm");
            sendUserMessage(user, new String[]{testInstanceId}, RequestUtil.getAppURL(getRequest()));
            addMessage("Reminder email sent to "+user.getFullName());
        } catch (MailException me) {
            addError(me.getMostSpecificCause().getMessage());
            return null;
        }

/*		
		StringBuffer msg = new StringBuffer();
		msg.append("Dear "+user.getFirstName()+",\n\n");
		msg.append("We would like to inform you that there is a questionnary ready for you to complete. ");
		msg.append("You can find it following the link below. ");
		msg.append("Simply login using your credentials, and choose the Tab 'MyTests'.\n\n");
		msg.append("The test id is "+testInstance.getObjectId()+"\n\n");
		msg.append("Thank you for your time.");        
		msg.append("\n\nLogin at: ").append(RequestUtil.getAppURL(getRequest()));


		//SimpleMailMessage message = new SimpleMailMessage();
		// message.setTo(user.getEmail());
		String subject = '[' + getText("webapp.name") + "] " + getText("reminder.email.subject");
		message.setText(msg.toString());
		message.setSubject(subject);
		message.setTo(user.getEmail());

		try{
			mailEngine.send(message);
			addMessage("Reminder email sent to "+user.getFullName());        
		}catch (MailException me){
			addError(me.getMostSpecificCause().getMessage());
			return null;
		}*/

		return null;	

	}
	
	public String done(){
		return "done";
	}



}
